#ifndef GDP_H
#define GDP_H

#include "Types.h"

#define CHANGED_RENDERMODE      0x0001
#define CHANGED_CYCLETYPE       0x0002
#define CHANGED_SCISSOR         0x0004
#define CHANGED_TMEM            0x0008
#define CHANGED_TILE            0x0010
#define CHANGED_COMBINE_COLORS  0x0020
#define CHANGED_COMBINE         0x0040
#define CHANGED_ALPHACOMPARE    0x0080
#define CHANGED_FOGCOLOR        0x0100
#define CHANGED_DEPTHSOURCE     0x0200
#define CHANGED_PRIMITIVEZ      0x0400
#define CHANGED_ENV_COLOR       0x0800
#define CHANGED_PRIM_COLOR      0x1000
#define CHANGED_BLENDCOLOR      0x2000
#define CHANGED_CONVERT         0x4000

#define TEXTUREMODE_NORMAL      0
#define TEXTUREMODE_TEXRECT     1
#define TEXTUREMODE_BGIMAGE     2
#define TEXTUREMODE_FRAMEBUFFER 3

#define LOADTYPE_BLOCK          0
#define LOADTYPE_TILE           1

struct gDPCombine
{
    union
    {
        struct
        {
            // muxs1
            unsigned    aA1     : 3;
            unsigned    sbA1    : 3;
            unsigned    aRGB1   : 3;
            unsigned    aA0     : 3;
            unsigned    sbA0    : 3;
            unsigned    aRGB0   : 3;
            unsigned    mA1     : 3;
            unsigned    saA1    : 3;
            unsigned    sbRGB1  : 4;
            unsigned    sbRGB0  : 4;

            // muxs0
            unsigned    mRGB1   : 5;
            unsigned    saRGB1  : 4;
            unsigned    mA0     : 3;
            unsigned    saA0    : 3;
            unsigned    mRGB0   : 5;
            unsigned    saRGB0  : 4;
        };

        struct
        {
            u32         muxs1, muxs0;
        };

        u64             mux;
    };
};

struct gDPTile
{
    u32 format, size, line, tmem, palette;

    union
    {
        struct
        {
            unsigned    mirrort : 1;
            unsigned    clampt  : 1;
            unsigned    pad0    : 30;

            unsigned    mirrors : 1;
            unsigned    clamps  : 1;
            unsigned    pad1    : 30;
        };

        struct
        {
            u32 cmt, cms;
        };
    };

    //FrameBuffer *frameBuffer;
    u32 maskt, masks;
    u32 shiftt, shifts;
    f32 fuls, fult, flrs, flrt;
    u32 uls, ult, lrs, lrt;
};

struct gDPInfo
{
    struct
    {
        union
        {
            struct
            {
                unsigned int alphaCompare : 2;
                unsigned int depthSource : 1;

//              struct
//              {
                    unsigned int AAEnable : 1;
                    unsigned int depthCompare : 1;
                    unsigned int depthUpdate : 1;
                    unsigned int imageRead : 1;
                    unsigned int clearOnCvg : 1;

                    unsigned int cvgDest : 2;
                    unsigned int depthMode : 2;

                    unsigned int cvgXAlpha : 1;
                    unsigned int alphaCvgSel : 1;
                    unsigned int forceBlender : 1;
                    unsigned int textureEdge : 1;
//              } renderMode;

                //struct
                //{
                    unsigned int c2_m2b : 2;
                    unsigned int c1_m2b : 2;
                    unsigned int c2_m2a : 2;
                    unsigned int c1_m2a : 2;
                    unsigned int c2_m1b : 2;
                    unsigned int c1_m1b : 2;
                    unsigned int c2_m1a : 2;
                    unsigned int c1_m1a : 2;
                //} blender;

                unsigned int blendMask : 4;
                unsigned int alphaDither : 2;
                unsigned int colorDither : 2;

                unsigned int combineKey : 1;
                unsigned int textureConvert : 3;
                unsigned int textureFilter : 2;
                unsigned int textureLUT : 2;

                unsigned int textureLOD : 1;
                unsigned int textureDetail : 2;
                unsigned int texturePersp : 1;
                unsigned int cycleType : 2;
                unsigned int unusedColorDither : 1; // unsupported
                unsigned int pipelineMode : 1;

                unsigned int pad : 8;

            };

            u64         _u64;

            struct
            {
                u32         l, h;
            };
        };
    } otherMode;

    gDPCombine combine;

    gDPTile tiles[8], *loadTile;

    struct
    {
        f32 r, g, b, a;
    } fogColor,  blendColor, envColor;

    struct
    {
        unsigned int i;
        f32 r, g, b, a;
        f32 z, dz;
    } fillColor;

    struct
    {
        u32 m;
        f32 l, r, g, b, a;
    } primColor;

    struct
    {
        f32 z, deltaZ;
    } primDepth;

    struct
    {
        u32 format, size, width, bpl;
        u32 address;
    } textureImage;

    struct
    {
        u32 format, size, width, height, bpl;
        u32 address, changed;
        u32 depthImage;
    } colorImage;

    u32 depthImageAddress;

    struct
    {
        u32 mode;
        f32 ulx, uly, lrx, lry;
    } scissor;

    struct
    {
        f32 k0, k1, k2, k3, k4, k5;
    } convert;

    struct
    {
        struct
        {
            f32 r, g, b, a;
        } center, scale, width;
    } key;

    struct
    {
        u32 width, height;
    } texRect;

    u32 changed;

    //u16 palette[256];
    u32 paletteCRC16[16];
    u32 paletteCRC256;
    u32 half_1, half_2;
    u32 textureMode;
    u32 loadType;
};

extern gDPInfo gDP;

void gDPSetOtherMode( u32 mode0, u32 mode1 );
void gDPSetPrimDepth( u16 z, u16 dz );
void gDPPipelineMode( u32 mode );
void gDPSetCycleType( u32 type );
void gDPSetTexturePersp( u32 enable );
void gDPSetTextureDetail( u32 type );
void gDPSetTextureLOD( u32 mode );
void gDPSetTextureLUT( u32 mode );
void gDPSetTextureFilter( u32 type );
void gDPSetTextureConvert( u32 type );
void gDPSetCombineKey( u32 type );
void gDPSetColorDither( u32 type );
void gDPSetAlphaDither( u32 type );
void gDPSetAlphaCompare( u32 mode );
void gDPSetDepthSource( u32 source );
void gDPSetRenderMode( u32 mode1, u32 mode2 );
void gDPSetCombine( s32 muxs0, s32 muxs1 );
void gDPSetColorImage( u32 format, u32 size, u32 width, u32 address );
void gDPSetTextureImage( u32 format, u32 size, u32 width, u32 address );
void gDPSetDepthImage( u32 address );
void gDPSetEnvColor( u32 r, u32 g, u32 b, u32 a );
void gDPSetBlendColor( u32 r, u32 g, u32 b, u32 a );
void gDPSetFogColor( u32 r, u32 g, u32 b, u32 a );
void gDPSetFillColor( u32 c );
void gDPSetPrimColor( u32 m, u32 l, u32 r, u32 g, u32 b, u32 a );
void gDPSetTile(u32 format, const u32 size, const u32 line, const u32 tmem, u32 tile,
               const u32 palette, const u32 cmt, const u32 cms, const u32 maskt, const u32 masks,
               const u32 shiftt, const u32 shifts );
void gDPSetTileSize( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt );
void gDPLoadTile( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt );
void gDPLoadBlock( u32 tile, u32 uls, u32 ult, u32 lrs, u32 dxt );
void gDPLoadTLUT( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt );
void gDPSetScissor( u32 mode, f32 ulx, f32 uly, f32 lrx, f32 lry );
void gDPFillRectangle( s32 ulx, s32 uly, s32 lrx, s32 lry );
void gDPSetConvert( s32 k0, s32 k1, s32 k2, s32 k3, s32 k4, s32 k5 );
void gDPSetKeyR( u32 cR, u32 sR, u32 wR );
void gDPSetKeyGB(u32 cG, u32 sG, u32 wG, u32 cB, u32 sB, u32 wB );
void gDPTextureRectangle( f32 ulx, f32 uly, f32 lrx, f32 lry, s32 tile, f32 s, f32 t, f32 dsdx, f32 dtdy );
void gDPTextureRectangleFlip( f32 ulx, f32 uly, f32 lrx, f32 lry, s32 tile, f32 s, f32 t, f32 dsdx, f32 dtdy );
void gDPFullSync();
void gDPTileSync();
void gDPPipeSync();
void gDPLoadSync();
void gDPNoOp();

#endif

